﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using RecommenderAlgorithmLibrary;
using System.Collections;

namespace AlgorithmTester
{
    public partial class MovielensAssessmentForm : Form
    {
        private DAL dal = new DAL();
        private IBCFandUBCFHybridAlgorithm algorithm = new IBCFandUBCFHybridAlgorithm();

        private int?[][] originalRatings;
        private float?[][] finalAllPredictedRatings;
        private float?[][] itemSimilarities;
        private float?[][] firstPredictedRatings;
        private float?[][] userSimilarities;
        private int USERNUMBER = 943;
        private int ITEMNUMBER = 1682;
        private int TOPN;
        private string statusText = "Ready";
        private List<int[]> testingList = new List<int[]>();

        public MovielensAssessmentForm()
        {
            InitializeComponent();
            InitializeComponents();
        }

        private void InitializeComponents()
        {
            this.comboBoxTrainingDataset.Items.Add("u1base");
            this.comboBoxTrainingDataset.Items.Add("u2base");
            this.comboBoxTrainingDataset.Items.Add("u3base");
            this.comboBoxTrainingDataset.Items.Add("u4base");
            this.comboBoxTrainingDataset.Items.Add("u5base");
            this.comboBoxTrainingDataset.SelectedIndex = 0;
            this.comboBoxTestingDataset.Items.Add("u1test");
            this.comboBoxTestingDataset.Items.Add("u2test");
            this.comboBoxTestingDataset.Items.Add("u3test");
            this.comboBoxTestingDataset.Items.Add("u4test");
            this.comboBoxTestingDataset.Items.Add("u5test");
            this.comboBoxTestingDataset.SelectedIndex = 0;

            InitializeBackgoundWorker();
        }

        private void InitializeBackgoundWorker()
        {
            backgroundWorker1.WorkerReportsProgress = true;
            backgroundWorker1.WorkerSupportsCancellation = true;
            backgroundWorker1.RunWorkerCompleted += new RunWorkerCompletedEventHandler(backgroundWorker1_RunWorkerCompleted);
            backgroundWorker1.ProgressChanged += new ProgressChangedEventHandler(backgroundWorker1_ProgressChanged);
        }

        private void buttonLoadData_Click(object sender, EventArgs e)
        {
            string trainingDataset = this.comboBoxTrainingDataset.SelectedItem.ToString();
            string testingDataset = this.comboBoxTestingDataset.SelectedItem.ToString();

            List<int[]> trainingList = dal.ReadTrainingRatings(trainingDataset);
            this.testingList = dal.ReadTrainingRatings(testingDataset);

            this.originalRatings=LoadArrayListtoRatingMatrix(trainingList);

            this.labelData.Text = "Data loaded.";
            this.labelData.ForeColor = Color.Green;
        }

        private int?[][] LoadArrayListtoRatingMatrix(List<int[]> ratingList)
        {
            int?[][] ratings = new int?[USERNUMBER][];
            for (int i = 0; i < USERNUMBER; i++)
            {
                int?[] rating = new int?[ITEMNUMBER];
                ratings[i] = rating;
            }

            foreach (int[] record in ratingList)
            {
                int userID = record[0];
                int itemID = record[1];
                int rating = record[2];

                ratings[userID - 1][itemID - 1] = rating;
            }

            return ratings;
        }

        private void buttonCalculate_Click(object sender, EventArgs e)
        {
            this.TOPN = Convert.ToInt32(this.textBoxTOPN.Text);
            this.backgroundWorker1.RunWorkerAsync();
        }

        private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
        {
            this.statusText = "Calculating item similarities...";
            backgroundWorker1.ReportProgress(0);
            itemSimilarities = algorithm.CalculateItemSimilarityUsingPearsonCorrelation(originalRatings);
            this.statusText = "Calculating ratings...";
            backgroundWorker1.ReportProgress(25);
            firstPredictedRatings = algorithm.PredictRatings(originalRatings, itemSimilarities, TOPN);
            this.statusText = "Calculating user similarities...";
            backgroundWorker1.ReportProgress(50);
            userSimilarities = algorithm.CalculateUserSimilarities(firstPredictedRatings);
            this.statusText = "Calculating final ratings...";
            backgroundWorker1.ReportProgress(75);
            finalAllPredictedRatings = algorithm.CalculateAllFinalRatings(originalRatings, userSimilarities, firstPredictedRatings, TOPN);
            backgroundWorker1.ReportProgress(100);
        }

        void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            this.toolStripStatusLabel1.Text = this.statusText;

            this.toolStripProgressBar1.Value = e.ProgressPercentage;
        }

        void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            this.toolStripStatusLabel1.Text = "Ready";
        }

        private void buttonAssess_Click(object sender, EventArgs e)
        {
            CalculateMAE();
        }

        private void CalculateMAE()
        {
            int totalNumber = 0;
            float MAE = 0;
            float sumDifferences = 0;

            foreach (int[] record in this.testingList)
            {
                int userID = record[0];
                int itemID = record[1];
                int rating = record[2];

                float? predictedRating = this.finalAllPredictedRatings[userID - 1][itemID - 1].Value;
                if (predictedRating != null)
                {
                    sumDifferences += Math.Abs(rating - predictedRating.Value);
                    totalNumber++;
                }
            }

            MAE = sumDifferences / (float)totalNumber;
            this.labelMAE.Text = MAE.ToString();
            this.labelMAE.ForeColor = Color.Green;
            this.labelRatingNumber.Text = this.testingList.Count.ToString();
            this.labelRatingNumber.ForeColor = Color.Green;
            this.labelAssessedNumber.Text = totalNumber.ToString();
            this.labelAssessedNumber.ForeColor = Color.Green;

            CalculateCoverage();
        }

        private void CalculateCoverage()
        {
            float predictedNumber = 0;
            for (int i = 0; i < USERNUMBER; i++)
            {
                for (int j = 0; j < ITEMNUMBER; j++)
                {
                    if (this.finalAllPredictedRatings[i][j].HasValue)
                    {
                        predictedNumber++;
                    }
                }
            }

            float coverage = (float)((predictedNumber-80000) / (USERNUMBER * ITEMNUMBER - 80000)*100);
            this.labelCoverage.Text = coverage.ToString() + "%";
            this.labelCoverage.ForeColor = Color.Green;
        }
    }
}
